﻿using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Linq;
using System.Security.Claims;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Logging;
using Microsoft.IdentityModel.Tokens;
using ECommerce.AuthService.Data;
using ECommerce.AuthService.Models;

namespace ECommerce.AuthService.Services;

/// <summary>
/// 认证服务实现
/// </summary>
public class AuthService : IAuthService
{
    private readonly UserManager<AppUser> _userManager;
    private readonly SignInManager<AppUser> _signInManager;
    private readonly AppDbContext _dbContext;
    private readonly JwtSettings _jwtSettings;
    private readonly ILogger<AuthService> _logger;

    /// <summary>
    /// 构造函数
    /// </summary>
    public AuthService(
        UserManager<AppUser> userManager,
        SignInManager<AppUser> signInManager,
        AppDbContext dbContext,
        JwtSettings jwtSettings,
        ILogger<AuthService> logger)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _dbContext = dbContext;
        _jwtSettings = jwtSettings;
        _logger = logger;
    }

    /// <summary>
    /// 用户注册
    /// </summary>
    public async Task<AuthResult> RegisterAsync(RegisterRequest request)
    {
        try
        {
            // 检查邮箱是否已存在
            var existingUser = await _userManager.FindByEmailAsync(request.Email);
            if (existingUser != null)
            {
                return new AuthResult { Success = false, Message = "邮箱已被注册" };
            }

            // 创建新用户
            var user = new AppUser
            {
                UserName = request.Email,
                Email = request.Email,
                FullName = request.FullName,
                RegistrationDate = DateTime.UtcNow,
                IsActive = true
            };

            // 保存用户到数据库
            var result = await _userManager.CreateAsync(user, request.Password);
            if (!result.Succeeded)
            {
                var errors = string.Join(", ", result.Errors.Select(e => e.Description));
                return new AuthResult { Success = false, Message = errors };
            }

            // 分配默认角色
            await _userManager.AddToRoleAsync(user, "User");

            _logger.LogInformation("用户注册成功: {Email}", request.Email);
            return await GenerateAuthResultAsync(user);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "注册失败: {Email}", request.Email);
            return new AuthResult { Success = false, Message = "注册过程中发生错误" };
        }
    }

    /// <summary>
    /// 用户登录
    /// </summary>
    public async Task<AuthResult> LoginAsync(LoginRequest request)
    {
        try
        {
            // 查找用户
            var user = await _userManager.FindByEmailAsync(request.Email);
            if (user == null)
            {
                return new AuthResult { Success = false, Message = "邮箱或密码错误" };
            }

            // 检查账户状态
            if (!user.IsActive)
            {
                return new AuthResult { Success = false, Message = "账户已被禁用" };
            }

            // 验证密码
            var result = await _signInManager.CheckPasswordSignInAsync(user, request.Password, false);
            if (!result.Succeeded)
            {
                return new AuthResult { Success = false, Message = "邮箱或密码错误" };
            }

            // 更新最后登录时间
            user.LastLoginTime = DateTime.UtcNow;
            await _userManager.UpdateAsync(user);

            _logger.LogInformation("用户登录成功: {Email}", request.Email);
            return await GenerateAuthResultAsync(user);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "登录失败: {Email}", request.Email);
            return new AuthResult { Success = false, Message = "登录过程中发生错误" };
        }
    }

    /// <summary>
    /// 刷新令牌
    /// </summary>
    public async Task<AuthResult> RefreshTokenAsync(string refreshToken)
    {
        try
        {
            // 查找有效的刷新令牌
            var tokenEntity = await _dbContext.RefreshTokens
                .FirstOrDefaultAsync(t => t.Token == refreshToken
                                        && !t.IsRevoked
                                        && t.ExpiresAt > DateTime.UtcNow);

            if (tokenEntity == null)
            {
                return new AuthResult { Success = false, Message = "无效的刷新令牌" };
            }

            // 查找用户
            var user = await _userManager.FindByIdAsync(tokenEntity.UserId.ToString());
            if (user == null || !user.IsActive)
            {
                return new AuthResult { Success = false, Message = "用户状态异常" };
            }

            // 吊销旧令牌
            tokenEntity.IsRevoked = true;
            tokenEntity.RevokedAt = DateTime.UtcNow;
            _dbContext.RefreshTokens.Update(tokenEntity);
            await _dbContext.SaveChangesAsync();

            _logger.LogInformation("令牌刷新成功: {UserId}", user.Id);
            return await GenerateAuthResultAsync(user);
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "刷新令牌失败");
            return new AuthResult { Success = false, Message = "刷新令牌过程中发生错误" };
        }
    }

    /// <summary>
    /// 注销
    /// </summary>
    public async Task<AuthResult> LogoutAsync(Guid userId, string refreshToken)
    {
        try
        {
            // 查找并吊销令牌
            var token = await _dbContext.RefreshTokens
                .FirstOrDefaultAsync(t => t.UserId == userId && t.Token == refreshToken);

            if (token != null)
            {
                token.IsRevoked = true;
                token.RevokedAt = DateTime.UtcNow;
                await _dbContext.SaveChangesAsync();
            }

            _logger.LogInformation("用户注销成功: {UserId}", userId);
            return new AuthResult { Success = true, Message = "注销成功" };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "注销失败: {UserId}", userId);
            return new AuthResult { Success = false, Message = "注销过程中发生错误" };
        }
    }

    /// <summary>
    /// 生成认证结果（包含令牌）
    /// </summary>
    private async Task<AuthResult> GenerateAuthResultAsync(AppUser user)
    {
        // 获取用户角色
        var roles = await _userManager.GetRolesAsync(user);

        // 生成JWT令牌
        var token = GenerateJwtToken(user, roles);

        // 生成刷新令牌
        var refreshToken = GenerateAndStoreRefreshToken(user.Id);

        return new AuthResult
        {
            Success = true,
            Token = token,
            RefreshToken = refreshToken,
            UserId = user.Id,
            Email = user.Email ?? string.Empty,
            Roles = roles
        };
    }

    /// <summary>
    /// 生成JWT令牌
    /// </summary>
    private string GenerateJwtToken(AppUser user, IList<string> roles)
    {
        var claims = new List<Claim>
        {
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
            new Claim(ClaimTypes.Email, user.Email ?? string.Empty),
            new Claim(ClaimTypes.Name, user.FullName),
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
        };

        // 添加角色声明
        claims.AddRange(roles.Select(role => new Claim(ClaimTypes.Role, role)));

        // 创建令牌
        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.Secret));
        var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

        var jwtToken = new JwtSecurityToken(
            issuer: _jwtSettings.Issuer,
            audience: _jwtSettings.Audience,
            claims: claims,
            expires: DateTime.UtcNow.AddMinutes(_jwtSettings.ExpiryMinutes),
            signingCredentials: credentials);

        return new JwtSecurityTokenHandler().WriteToken(jwtToken);
    }

    /// <summary>
    /// 生成并存储刷新令牌
    /// </summary>
    private string GenerateAndStoreRefreshToken(Guid userId)
    {
        // 生成随机令牌
        var randomNumber = new byte[32];
        using (var rng = RandomNumberGenerator.Create())
        {
            rng.GetBytes(randomNumber);
        }
        var refreshToken = Convert.ToBase64String(randomNumber);

        // 存储到数据库
        var tokenEntity = new RefreshToken
        {
            UserId = userId,
            Token = refreshToken,
            ExpiresAt = DateTime.UtcNow.AddDays(_jwtSettings.RefreshTokenExpiryDays),
            IsRevoked = false
        };

        _dbContext.RefreshTokens.Add(tokenEntity);
        _dbContext.SaveChanges();

        return refreshToken;
    }
}